﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace WpfGenetic
{
    /// <summary>
    /// Логика взаимодействия для SettingsWindow.xaml
    /// </summary>
    public partial class SettingsWindow : Window
    {
        private GeneticConfiguration BufferConfig { get; set; }    // Буферная конфигурация для редактирования в окне настроек
        private GeneticConfiguration MainConfig { get; set; }      // Конфигурация, принадлежащая основному окну

        public SettingsWindow(GeneticConfiguration conf)
        {
            InitializeComponent();

            BufferConfig = (GeneticConfiguration)conf.Clone();

            MainConfig = conf;

            this.DataContext = BufferConfig;

            // Выставляем значения чек боксов
            UpdateCheckBox();

            // Определяем какие нужны для этих шифров
            UpdateCipherContext();
        }

        #region Обработчики событий

        /// <summary>
        /// Сохраняет в файл конфигурацию из окна настроек
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SaveStartingConfig_Click(object sender, RoutedEventArgs e)
        {
            string configPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"Config/GeneticConfig.json");
            BufferConfig.SaveJsonInFile(configPath);

            MessageBox.Show("Конфигурация сохранена.");
        }

        /// <summary>
        /// Загружает в окно настроек конфигурацию, сохранённую в файл
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void LoadStartingConfig_Click(object sender, RoutedEventArgs e)
        {
            string configPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"Config/GeneticConfig.json");
            BufferConfig = GeneticConfigCreator.Factory(configPath);
            UpdateCheckBox();
            this.DataContext = BufferConfig;
        }

        /// <summary>
        /// Устанавливает в окне настроек конфигурацию по умолчанию
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void LoadDefaultConfig_Click(object sender, RoutedEventArgs e)
        {
            BufferConfig = new GeneticConfiguration();
            UpdateCheckBox();
            this.DataContext = BufferConfig;
        }

        /// <summary>
        /// Открывает окно помощи с пояснениями по конфигурации
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void HelpMenu_Click(object sender, RoutedEventArgs e)
        {
            HelpSettingWindow settingsWindow = new()
            {
                Owner = this
            };

            settingsWindow.Show();
        }

        /// <summary>
        /// Обработка события установки настроек конфигурации как действующей
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Bt_SetConf_Click(object sender, RoutedEventArgs e)
        {
            StringBuilder sb = new();
            GetTextBoxErrors(sb, grid_Main);
            string message = sb.ToString();

            if (checkBox_BIGRAMS_TYPE.IsChecked == false && checkBox_TRIGRAMS_TYPE.IsChecked == false 
                && (checkBox_INDEX_OF_MATCHES_FLAG.IsChecked == false || BufferConfig.CIPHER_TYPE == 1))
            {
                message += "Должен быть активирован хотя бы один параметр фитнесс-функции\r\n";
            }

            if (BufferConfig.CIPHER_TYPE == 0 &&
                Binary.GetMaxIntValue(BufferConfig.RANK_KEY_LENGTH) < BufferConfig.MAX_START_KEY_LENGTH)
            {
                message += "Начальная длина ключа не может быть больше максимальной длины ключа\r\n";
            }

            if (BufferConfig.CIPHER_TYPE == 1 &&
                Binary.GetMaxIntValue(BufferConfig.RANK_HORIZONTAL_KEY_LENGTH) < BufferConfig.HORIZONTAL_MAX_KEY_LENGTH)
            {
                message += "Начальная длина горизонтального ключа не может быть больше максимальной длины ключа\r\n";
            }

            if (BufferConfig.CIPHER_TYPE == 1 &&
                Binary.GetMaxIntValue(BufferConfig.RANK_VERTICAL_KEY_LENGTH) < BufferConfig.VERTICAL_MAX_KEY_LENGTH)
            {
                message += "Начальная длина вертикального ключа не может быть больше максимальной длины ключа\r\n";
            }

            if (message != "")
            {
                MessageBox.Show(message);
                return;
            }

            MainConfig.CopyIn(BufferConfig);

            this.DialogResult = true;
        }

        #region Checkbox`ы
        private void CheckBox_BIGRAMS_TYPE_Checked(object sender, RoutedEventArgs e)
        {
            tBox_BIGRAMS_TYPE.IsEnabled = true;
            tBox_BIGRAMS_TYPE.Text = "1";
            BufferConfig.BIGRAMS_TYPE = 1;
        }

        private void CheckBox_BIGRAMS_TYPE_Unchecked(object sender, RoutedEventArgs e)
        {
            tBox_BIGRAMS_TYPE.IsEnabled = false;
            tBox_BIGRAMS_TYPE.Text = "";
            BufferConfig.BIGRAMS_TYPE = null;
        }

        private void CheckBox_TRIGRAMS_TYPE_Checked(object sender, RoutedEventArgs e)
        {
            tBox_TRIGRAMS_TYPE.IsEnabled = true;
            tBox_TRIGRAMS_TYPE.Text = "1";
            BufferConfig.TRIGRAMS_TYPE = 1;
        }

        private void CheckBox_TRIGRAMS_TYPE_Unchecked(object sender, RoutedEventArgs e)
        {
            tBox_TRIGRAMS_TYPE.IsEnabled = false;
            tBox_TRIGRAMS_TYPE.Text = "";
            BufferConfig.TRIGRAMS_TYPE = null;
        }

        private void CheckBox_INDEX_OF_MATCHES_FLAG_Checked(object sender, RoutedEventArgs e)
        {
            BufferConfig.INDEX_OF_MATCHES_FLAG = true;
        }

        private void CheckBox_INDEX_OF_MATCHES_FLAG_Unchecked(object sender, RoutedEventArgs e)
        {
            BufferConfig.INDEX_OF_MATCHES_FLAG = false;
        }

        private void CheckBox_AlphabetSpecial_Checked(object sender, RoutedEventArgs e)
        {
            tBox_AlphabetSpecial.IsEnabled = true;
            BufferConfig.USING_ALPHABET_FOR_GENERATION = true;
        }

        private void CheckBox_AlphabetSpecial_Unchecked(object sender, RoutedEventArgs e)
        {
            tBox_AlphabetSpecial.IsEnabled = false;
            BufferConfig.USING_ALPHABET_FOR_GENERATION = false;
        }

        #endregion

        #endregion

        #region Вспомогательные функции

        /// <summary>
        /// Для разных шифров отображаются разные настройки
        /// </summary>
        private void UpdateCipherContext()
        {
            // Шифр Виженера
            if (BufferConfig.CIPHER_TYPE == 0)
            {
                dp_MIN_START_KEY_LENGTH.Visibility = Visibility.Visible;
                dp_MAX_START_KEY_LENGTH.Visibility = Visibility.Visible;
                dp_RANK_KEY_LENGTH.Visibility = Visibility.Visible;
                dp_INDEX_OF_MATCHES_FLAG.Visibility = Visibility.Visible;

                dp_HORIZONTAL_MIN_KEY_LENGTH.Visibility = Visibility.Collapsed;
                dp_HORIZONTAL_MAX_KEY_LENGTH.Visibility = Visibility.Collapsed;
                dp_RANK_HORIZONTAL_KEY_LENGTH.Visibility = Visibility.Collapsed;
                dp_VERTICAL_MIN_KEY_LENGTH.Visibility = Visibility.Collapsed;
                dp_VERTICAL_MAX_KEY_LENGTH.Visibility = Visibility.Collapsed;
                dp_RANK_VERTICAL_KEY_LENGTH.Visibility = Visibility.Collapsed;
            }
            else // Перестановочный шифр
            if (BufferConfig.CIPHER_TYPE == 1)
            {
                dp_MIN_START_KEY_LENGTH.Visibility = Visibility.Collapsed;
                dp_MAX_START_KEY_LENGTH.Visibility = Visibility.Collapsed;
                dp_RANK_KEY_LENGTH.Visibility = Visibility.Collapsed;
                dp_INDEX_OF_MATCHES_FLAG.Visibility = Visibility.Collapsed;

                dp_HORIZONTAL_MIN_KEY_LENGTH.Visibility = Visibility.Visible;
                dp_HORIZONTAL_MAX_KEY_LENGTH.Visibility = Visibility.Visible;
                dp_RANK_HORIZONTAL_KEY_LENGTH.Visibility = Visibility.Visible;
                dp_VERTICAL_MIN_KEY_LENGTH.Visibility = Visibility.Visible;
                dp_VERTICAL_MAX_KEY_LENGTH.Visibility = Visibility.Visible;
                dp_RANK_VERTICAL_KEY_LENGTH.Visibility = Visibility.Visible;
            }
        }

        /// <summary>
        /// Функция проходится по дереву элементов и проверяет наличие ошибок у textbox`ов
        /// </summary>
        /// <param name="sb"></param>
        /// <param name="obj"></param>
        private static void GetTextBoxErrors(StringBuilder sb, DependencyObject obj)
        {
            foreach (object child in LogicalTreeHelper.GetChildren(obj))
            {
                TextBox? element = child as TextBox;
                if (element is not null)
                {
                    if (Validation.GetHasError(element))
                    {
                        sb.Append(element.Text + ":");
                        foreach (ValidationError error in Validation.GetErrors(element))
                        {
                            sb.Append("  " + error.ErrorContent.ToString() + "\r\n");
                        }
                    }
                }
                else
                {
                    DependencyObject? newObj = child as DependencyObject;
                    if (newObj is not null)
                    {
                        GetTextBoxErrors(sb, newObj);
                    }
                }
            }
        }

        /// <summary>
        /// Обновляет состояние чек боксов исходя из конфигурации, нужна для начальной настройки
        /// </summary>
        private void UpdateCheckBox()
        {
            if (BufferConfig.BIGRAMS_TYPE is null)
            {
                tBox_BIGRAMS_TYPE.IsEnabled = false;
                checkBox_BIGRAMS_TYPE.IsChecked = false;
            }
            else
            {
                tBox_BIGRAMS_TYPE.IsEnabled = true;
                checkBox_BIGRAMS_TYPE.IsChecked = true;
            }

            if (BufferConfig.TRIGRAMS_TYPE is null)
            {
                tBox_TRIGRAMS_TYPE.IsEnabled = false;
                checkBox_TRIGRAMS_TYPE.IsChecked = false;
            }
            else
            {
                tBox_TRIGRAMS_TYPE.IsEnabled = true;
                checkBox_TRIGRAMS_TYPE.IsChecked = true;
            }

            if (BufferConfig.INDEX_OF_MATCHES_FLAG)
            {
                checkBox_INDEX_OF_MATCHES_FLAG.IsChecked = true;
            }
            else
            {
                checkBox_INDEX_OF_MATCHES_FLAG.IsChecked = false;
            }

            if (BufferConfig.USING_ALPHABET_FOR_GENERATION)
            {
                tBox_AlphabetSpecial.IsEnabled = true;
                checkBox_AlphabetSpecial.IsChecked = true;
            }
            else
            {
                tBox_AlphabetSpecial.IsEnabled = false;
                checkBox_AlphabetSpecial.IsChecked = false;
            }
        }


        #endregion
    }
}
